package app_kvEcs;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import logger.LogSetup;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;

//TO-DO M3
public class ECSClient {
    private Logger logger = Logger.getRootLogger();
    private BufferedReader br;
    private ECS ecs;
    private String ori_command = "";
    private int command = 0;
    private int numberOfNodes = 0;
    private String logLevel = "";

    private static final int INIT_COMMAND = 1;
    private static final int START_COMMAND = 2;
    private static final int STOP_COMMAND = 3;
    private static final int SHUTDOWN_COMMAND = 4;
    private static final int ADD_COMMAND = 5;
    private static final int REMOVE_COMMAND = 6;
    private static final int ERROR_COMMAND = 7;
    private static final int HELP_COMMAND = 8;
    private static final int RETURN_COMMAND = 9;
    private static final int LOGLEVEL_COMMAND = 10;
    private static final int QUIT_COMMAND = 11;
    private static final String PROMPT = "ECSClient> ";

    /**
     * Constructor
     * 
     * @throws IOException
     */
     public ECSClient(String confile) {
        this.ecs = new ECS(confile);
    }

    /**
     * Start the human interface
     * 
     * @throws Exception
     */
    public void run() {
        System.out
                .println(PROMPT
                        + "Welcome to ECS Client, please type in command or type help!");

        while (true) {
            System.out.print(PROMPT);
            command = readCommand();
            switch (command) {
            case INIT_COMMAND:
                try {
                    ecs.initService(numberOfNodes);
                    logger.info("Success init "+numberOfNodes+" servers");
                } catch (IllegalArgumentException e) {
                    logger.info(PROMPT + "Please check your input.");
                    break;
                }
                break;
            case START_COMMAND:
                ecs.start();
                logger.info("Success start "+numberOfNodes+" servers");
                break;
            case STOP_COMMAND:
                ecs.stop();
                break;
            case SHUTDOWN_COMMAND:
                ecs.shutDown();
                break;
            case ADD_COMMAND:
                ecs.addNode(); //TODO parse 参数
                break;
            case REMOVE_COMMAND:
                ecs.removeNode();
                break;
            case LOGLEVEL_COMMAND:
                if (LogSetup.isValidLevel(logLevel)) {
                    String level = setLevel(logLevel);
                    if (logLevel.equals(LogSetup.UNKNOWN_LEVEL)) {
                        System.out
                                .println(PROMPT
                                        + "Error! No valid log level! Use command \"help\" to get help!");
                    } else {
                        logger.info(PROMPT
                                + "Log level changed to level " + level);
                    }
                } else {
                    System.out
                            .println(PROMPT
                                    + "Error! No valid log level! Use command \"help\" to get help!");
                }
                break;
            case QUIT_COMMAND:
                // if (!isPortAvailable) {
                // logger.info(PROMPT + "No network");
                // break;
                // }
                logger.info("Quit Application!");
                logger.info(PROMPT + "Application exit!");
                System.exit(-1);
                break;
            case ERROR_COMMAND:
                logger.info(PROMPT
                        + "Error command! Using command \"help\" to get help!");
                logger.warn("Error command!" + ori_command);
                break;
            case HELP_COMMAND:
                printHelp();
                logger.info("Get help!");
                break;
            case RETURN_COMMAND:
                logger.info("ECSClient> ");
                break;
            default:
                logger.warn("What happened?");
                break;

            }
        }
    }

    /**
     * Parse the command from user
     * 
     * @return the command type representing by an integer
     */
    private int readCommand() {
        br = new BufferedReader(new InputStreamReader(System.in));
        try {
            ori_command = br.readLine();
            String temp[] = ori_command.split(" ");
            if (temp[0].equalsIgnoreCase("init")) {
                if (temp.length == 2) {
                    numberOfNodes = Integer.parseInt(temp[1]);
                    //logger.info(numberOfNodes);
                    return INIT_COMMAND;
                } else {
                    return ERROR_COMMAND;
                }
            } else if (temp[0].equalsIgnoreCase("start")) {
                if (temp.length == 1) {
                    return START_COMMAND;
                } else {
                    return ERROR_COMMAND;
                }
            } else if (temp[0].equalsIgnoreCase("stop")) {
                if (temp.length == 1) {
                    return STOP_COMMAND;
                } else {
                    return ERROR_COMMAND;
                }
            } else if (temp[0].equalsIgnoreCase("shutDown")) {
                if (temp.length == 1) {
                    return SHUTDOWN_COMMAND;
                } else {
                    return ERROR_COMMAND;
                }
            } else if (temp[0].equalsIgnoreCase("addNode")) {
                if (temp.length == 1) {
                    return ADD_COMMAND;
                } else {
                    return ERROR_COMMAND;
                }
            } else if (temp[0].equalsIgnoreCase("removeNode")) {
                if (temp.length == 1) {
                    return REMOVE_COMMAND;
                } else {
                    return ERROR_COMMAND;
                }
            } else if (temp[0].equalsIgnoreCase("loglevel")) {
                if (temp.length == 2) {
                    logLevel = temp[1];
                    return LOGLEVEL_COMMAND;
                } else {
                    return ERROR_COMMAND;
                }
            } else if (temp[0].equalsIgnoreCase("quit")) {
                return QUIT_COMMAND;
            } else if (temp[0].equalsIgnoreCase("help")) {
                return HELP_COMMAND;
            } else if (temp[0].isEmpty()) {
                return RETURN_COMMAND;
            } else {
                return ERROR_COMMAND;
            }
        } catch (IOException e) {
            e.printStackTrace();
            logger.error(e.getMessage());
            return ERROR_COMMAND;
        }
    }

    public String setLevel(String levelString) {
        if (levelString.equals(Level.ALL.toString())) {
            logger.setLevel(Level.ALL);
            return Level.ALL.toString();
        } else if (levelString.equals(Level.DEBUG.toString())) {
            logger.setLevel(Level.DEBUG);
            return Level.DEBUG.toString();
        } else if (levelString.equals(Level.INFO.toString())) {
            logger.setLevel(Level.INFO);
            return Level.INFO.toString();
        } else if (levelString.equals(Level.WARN.toString())) {
            logger.setLevel(Level.WARN);
            return Level.WARN.toString();
        } else if (levelString.equals(Level.ERROR.toString())) {
            logger.setLevel(Level.ERROR);
            return Level.ERROR.toString();
        } else if (levelString.equals(Level.FATAL.toString())) {
            logger.setLevel(Level.FATAL);
            return Level.FATAL.toString();
        } else if (levelString.equals(Level.OFF.toString())) {
            logger.setLevel(Level.OFF);
            return Level.OFF.toString();
        } else {
            return LogSetup.UNKNOWN_LEVEL;
        }
    }

    /**
     * help information
     */
    private void printHelp() {
        StringBuilder sb = new StringBuilder();
        sb.append(PROMPT).append("ECS CLIENT HELP (Usage):\n");
        sb.append("-----------------------------------------------------------------------------------------------\n");
        sb.append("init <number>");
        sb.append("\t Randomly choose <numberOfNodes> servers from the available machines \n");
        sb.append("\t\t and start the KVServer by issuing a SSH call to the\n");
        sb.append("start");
        sb.append("\t\t Starts the storage service by calling start() on all KVServer instances\n");
        sb.append("stop");
        sb.append("\t\t Stops the service; all participating KVServers are stopped for\n");
        sb.append("\t\t processing client requests but the processes remain running. \n");
        sb.append("shutdown");
        sb.append("\t Stops all server instances and exits the remote processes. \n");
        sb.append("addNode");
        sb.append("\t\t Add a new node to the storage service at an arbitrary position.\n");
        sb.append("removeNode");
        sb.append("\t Remove a node from the storage service at an arbitrary position.\n");
        sb.append("logLevel");
        sb.append("\t Sets the logger to the specified log level");
        sb.append("ALL | DEBUG | INFO | WARN | ERROR | FATAL | OFF \n");
        sb.append("quit ");
        sb.append("\t\t Tears down the active connection to the server and exits the program.");
        logger.info(sb.toString());
    }

    public static void main(String[] args) {
        String confile = null;
        try {
            new LogSetup("logs/ecs/ecs.log", Level.ALL);
            confile = args[0];
        } catch (IOException e) {
            System.out.println("Please check your log_dir");
        }
        ECSClient c = new ECSClient(confile);


        c.run();
    }
}
